home *** CD-ROM | disk | FTP | other *** search
- /*=============================================================*\
- * ll.c - link looker *
- * Copyright (C) 1994 by The Software System and lilo *
- * Written by George Shearer (george@sphinx.biosci.wayne.edu) *
- * Cleaned up to usability by lilo. :) *
- * *
- * September, 1994 - added help, version info and made the *
- * program so you can actually use it. :) *
- * --lilo *
- * *
- * October 14, 1994 - cleaned up output flushing so you can *
- * actually watch in something like real *
- * time. :) --lilo *
- * *
- * October 28, 1994 - kill -1 will now produce a list of SPLIT *
- * servers. -Doc *
- * *
- * November 4, 1994 - should compile on non-POSIX systems now. *
- * use -DHPSUCKS for HP-sUX systems 9.0x *
- * November 15, 1994 - fixed a small bug in lilo's -h checker *
- \*=============================================================*/
-
- /* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- /* Compiling examples:
-
- regular old ANSI/C cc:
- cc -O -s -o ll ll.c
-
- HP-UX cc:
- cc +O3 -Aa -s -DHPSUCKS -o ll ll.c
-
- GNU GCC:
-
- Linux:
- gcc -O2 -fomit-frame-pointer -funroll-loops -m486 -s -Wall -o ll ll.c
-
- BSD, SunOS 4.1.x, Slowaris 2.x, NeXT:
- gcc -O2 -funroll-loops -s -Wall -o ll ll.c */
-
- #define VERSION "1.06"
- #define BUFSIZE 400 /* IRC Server buffer */
- #define SERVER "dewey.cc.utexas.edu" /* IRC Server */
- #define PORT 6667 /* IRC Port */
- #define LDELAY 30 /* Loop delay seconds*/
- #define TIMEOUT 30 /* connection timeout*/
-
- #define ESTABLISHED 1
- #define INPROGRESS 2
- #define SPLIT 1
-
- #ifdef HPSUCKS
- #define _INCLUDE_HPUX_SOURCE
- #define _INCLUDE_XOPEN_SOURCE
- #define _INCLUDE_POSIX_SOURCE
- #endif
-
- #include <sys/time.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <errno.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <arpa/inet.h>
- #include <pwd.h>
-
- unsigned short int session=0,link_count=0;
- char in[BUFSIZE],out_buf[BUFSIZE],hostname[64];
- char *ins=in;
- char serverhost[81], nick[10], user[10], realname[81], lasttime[81];
- time_t ltime;
-
- struct irc_server {
- char *name;
- char *link;
- unsigned short int status;
- time_t time;
- struct irc_server *next;
- } *sl1=(struct irc_server *)0,*sl2=(struct irc_server *)0;
-
- void do_ping(char *,char *);
- void do_001(char *,char *);
- void do_error(char *,char *);
- void do_364(char *,char *);
- void do_365(char *,char *);
-
- /* prototyping is lame when the function is in the same
- code, lilo outta just move the function before all
- other functions that call it :-) */
- char *stamp(time_t);
-
- struct parsers {
- char *cmd;
- void (*func)(char *,char *);
- } parsefuns[] = {
- { "PING", (void (*)())do_ping },
- { "001", (void (*)())do_001 },
- { "364",(void (*)())do_364 },
- { "365", (void (*)())do_365},
- { "ERROR",(void (*)())do_error},
- { (char *)0,(void (*)())0 }
- };
-
- struct sockaddr_in server;
- int sock=0;
-
- #ifndef sys_errlist
- extern char *sys_errlist[];
- #endif
-
- #ifndef errno
- extern int errno;
- #endif
-
- char *
- mystrerror(int err) {
- return(sys_errlist[err]);
- }
-
- unsigned long int
- resolver(char *host) {
- unsigned long int ip=0L;
-
- if(host && *host && (ip=inet_addr(host))==-1) {
- struct hostent *he;
- int x=0;
-
- while(!(he=gethostbyname((char *)host)) && x++<3) {
- fprintf(stderr,"."); fflush(stderr);
- sleep(1);
- }
- ip=(x<3) ? *(unsigned long *)he->h_addr_list[0] : 0L;
- }
-
- return(ip);
- }
-
- void
- clean_sl2(void) {
- while(sl2) {
- struct irc_server *temp=sl2->next;
- if(sl2->name)
- free(sl2->name);
- if(sl2->link)
- free(sl2->link);
- free(sl2);
- sl2=temp;
- }
- sl2=(struct irc_server *)0;
- }
-
- void
- exit_program(char *why) {
- fprintf(stderr,"\nExiting program. (%s)\n",why);
-
- if(sock)
- close(sock);
-
- while(sl1) {
- struct irc_server *temp=sl1->next;
- if(sl1->name)
- free(sl1->name);
- if(sl1->link)
- free(sl1->link);
- free(sl1);
- sl1=temp;
- }
-
- clean_sl2();
-
- if(in)
- free(in);
-
- exit(0);
- }
-
- int mystrccmp(register char *s1,register char *s2) {
- while((((*s1)>='a'&&(*s1)<='z')?(*s1)-32:*s1)==
- (((*s2)>='a'&&(*s2)<='z')?(*s2++)-32:*s2++))
- if(*s1++==0) return 0;
- return (*(unsigned char *)s1-*(unsigned char *)--s2);
- }
-
- char *mstrcpy(char **to,char *from) {
- if(from) {
- if((*to=(char *)malloc(strlen(from)+1)))
- strcpy(*to,from);
- }
- else
- *to=(char *)0;
- return(*to);
- }
-
- char *digtoken(char **string,char *match) {
- if(string && *string && **string) {
- while(**string && strchr(match,**string))
- (*string)++;
- if(**string) { /* got something */
- char *token=*string;
- if((*string=strpbrk(*string,match))) {
- *(*string)++=(char)0;
- while(**string && strchr(match,**string))
- (*string)++;
- }
- else
- *string = ""; /* must be at the end */
- return(token);
- }
- }
- return((char *)0);
- }
-
- void signal_handler(void) {
- exit_program("caught signal");
- }
-
- void signal_alarm(void) {
- exit_program("timed out waiting for server interaction.");
- }
-
- void
- out(void) {
- int length=strlen(out_buf);
- errno=0;
- if(write(sock,out_buf,length)!=length)
- exit_program(mystrerror(errno));
- }
-
- void
- init_server(void) {
- int length;
-
- sprintf(out_buf,"USER %s %s %s :%s\nNICK %s\nMODE %s +is", \
- user, user, user, realname, nick, nick);
- length=strlen(out_buf);
-
- errno=0;
-
- if(write(sock,out_buf,length)==length) {
- fputs("established\n",stderr);
- session=ESTABLISHED;
- alarm(TIMEOUT);
- sprintf(out_buf,"LINKS\n");
- out();
- }
- else
- exit_program(mystrerror(errno));
- }
-
- void
- heartbeat(void) {
- strcpy(out_buf,"LINKS\n");
- out();
- signal(SIGALRM,(void (*)())heartbeat);
- alarm(LDELAY);
- }
-
- void
- do_364(char *from,char *left) {
- struct irc_server *serv;
- char *sv1,*sv2;
- char *nick;
-
- serv=(struct irc_server *)malloc(sizeof(struct irc_server));
- serv->next=sl2;
-
- serv->status=0;
- nick=digtoken(&left," ");
- sv1=digtoken(&left," ");
- sv2=digtoken(&left," ");
-
- mstrcpy(&serv->name,sv1);
- mstrcpy(&serv->link,sv2);
- sl2=serv;
- }
-
- int
- findserv(struct irc_server *serv,char *name) {
- for(;serv;serv=serv->next)
- if(!mystrccmp(name,serv->name))
- return(1);
- return(0);
- }
-
- void
- show_split(void) {
- struct irc_server *serv=sl1;
-
- signal(SIGHUP,(void (*)())show_split);
- for(;serv;serv=serv->next) {
- if(serv->status & SPLIT) {
- printf("%s SPLIT: %s [%s]\n",stamp(serv->time),serv->name,serv->link);
- fflush(stdout);
- }
- }
- }
-
- void
- do_365(char *from,char *left) {
- struct irc_server *serv=sl1;
-
- for(;serv;serv=serv->next) {
- if(!findserv(sl2,serv->name)) {
- if(!(serv->status & SPLIT)) {
- serv->time=time(NULL);
- printf("%s SPLIT: %s [%s]\n",stamp(serv->time),serv->name,serv->link);
- fflush(stdout);
- serv->status|=SPLIT;
- }
- }
- else
- if(serv->status & SPLIT) {
- serv->time=time(NULL);
- printf("%s MERGE: %s [%s]\n",stamp(serv->time),serv->name,serv->link);
- fflush(stdout);
- serv->status&=~SPLIT;
- }
- }
-
- serv=sl2;
-
- for(;serv;serv=serv->next) {
- if(!findserv(sl1,serv->name)) {
- struct irc_server *serv2;
-
- serv2=(struct irc_server *)malloc(sizeof(struct irc_server));
- serv2->next=sl1;
- serv2->status=0;
- mstrcpy(&serv2->name,serv->name);
- mstrcpy(&serv2->link,serv->link);
- sl1=serv2;
- serv2->time=time(NULL);
- if(link_count) {
- printf("%s ADDED: %s [%s]\n",stamp(serv2->time),serv->name,serv->link);
- fflush(stdout);
- }
- }
- }
-
- link_count=1;
- clean_sl2();
- }
-
- void
- do_ping(char *from,char *left) {
- sprintf(out_buf,"PING :%s\n",hostname);
- out();
- }
-
- void
- do_001(char *from,char *left) {
- fprintf(stderr,"Logged into server %s as nickname %s\n\n",from,nick);
- fflush(stderr);
- alarm(0);
- signal(SIGALRM,(void (*)())heartbeat);
- alarm(LDELAY);
- }
-
- void
- do_error(char *from,char *left) {
- fprintf(stderr,"Server error: %s\n",left);
- fflush(stderr);
- }
-
- void
- parse2(void) {
- char *from,*cmd,*left;
-
- if(*ins==':') {
- if(!(cmd=strchr(ins,' ')))
- return;
- *cmd++=(char)0;
- from=ins+1;
- }
- else {
- cmd=ins;
- from=(char *)0;
- }
- if((left=strchr(cmd,' '))) {
- int command;
- *left++=(char)0;
- left=(*left==':') ? left+1 : left;
- for(command=0;parsefuns[command].cmd;command++) {
- if(!mystrccmp(parsefuns[command].cmd,cmd)) {
- parsefuns[command].func(from,left);
- break;
- }
- }
- }
- }
-
- void
- parse(int length) {
- char *s=in;
-
- *(ins+length)=(char)0;
-
- for(;;) {
- ins=s;
- while(*s && *s!=(char)13 && *s!=(char)10)
- s++;
- if(*s) {
- while(*s && (*s==(char)13 || *s==(char)10))
- *s++=(char)0;
- parse2();
- }
- else
- break;
- }
- strcpy(in,ins);
- ins=in+(s-ins);
- }
-
- void
- process_server(void) {
- int x=0;
-
- for(;;) {
- fd_set rd,wr;
- struct timeval timeout;
-
- timeout.tv_usec=0; timeout.tv_sec=1;
- FD_ZERO(&rd); FD_ZERO(&wr);
-
- FD_SET(sock,&rd);
- if(session==INPROGRESS)
- FD_SET(sock,&wr);
-
- errno=0;
-
- #ifdef HPSUCKS
- select((size_t)FD_SETSIZE,(int *)&rd,(int *)&wr,(int *)0,(session==INPROGRESS)?(const struct timeval *)&timeout:(const struct timeval *)0);
- #else
- select(getdtablesize(),(fd_set *)&rd,(fd_set *)&wr,(fd_set *)0,(session==INPROGRESS)?(struct timeval *)&timeout:(struct timeval *)0);
- #endif
-
- if(errno==EINTR)
- continue;
-
- errno=0;
- if(session==INPROGRESS) {
- if(FD_ISSET(sock,&wr)) {
- init_server();
- continue;
- }
- else {
- if(x++>=TIMEOUT)
- exit_program("connection timed out");
- fprintf(stderr,"."); fflush(stderr);
- }
- }
-
- if(FD_ISSET(sock,&rd)) {
- int length=read(sock,ins,BUFSIZE-(ins-in));
-
- if(length<1) {
- if(session!=INPROGRESS) {
- if(!errno) {
- fputs("Connection closed by foreign host.",stderr);
- errno=ENOTCONN;
- }
- else
- fprintf(stderr,"Connection to %s closed.\n",
- inet_ntoa(server.sin_addr));
- fflush(stderr);
- }
- exit_program(mystrerror(errno));
- }
- if(strpbrk(in,"\x0a\x0d"))
- parse(length);
- else
- ins=(BUFSIZE-((ins+length)-in)<1)?in:ins+length;
- }
- }
- }
-
- char *stamp(time_t ltime) {
- strftime(lasttime, 81, "%x %X", localtime(<ime));
- return (char *) &lasttime;
- }
-
- void
- main(int argc,char *argv[]) {
- unsigned short int sport=PORT;
- unsigned int loop;
- struct passwd *passent;
-
- fprintf(stderr, "Link Looker v%s, written and designed by Dr. Delete.\n" \
- " Enhanced by lilo.\n" \
- "Type '%s -h' or '%s --help' for more information.\n\n",
- VERSION, argv[0], argv[0]);
-
- for(loop=1; loop<argc; loop++) {
- if(!strcmp("-h", argv[loop]) || !strcmp("--help", argv[loop])) {
- fprintf(stderr,"Format:\n\n" \
- " %s [-h] [<nick> [<server>[:<port>] ['<real name field>' " \
- "[<username>]]]]\n\n where:\n\n" \
- " <nick> is the nickname to be used (default is userid),\n" \
- " <server> is the hostname of the server to be used,\n" \
- " <port> is a four digit port number (default is 6667),\n" \
- " <real name field> is a description of the user (default is gecos info), and\n" \
- " <username> is the user account field, used only if identd\n" \
- " has not been enabled on the user's system.\n", \
- argv[0]);
- exit(1);
- }
- }
-
- passent=getpwuid(getuid());
-
- if(argc>1)
- strncpy(nick,argv[1],9);
- else
- strncpy(nick,passent->pw_name,9);
-
- if(argc>2) {
- char *port=strchr(argv[2],':');
- sport=(port)?atoi(port+1):sport;
- strncpy(serverhost,argv[2],80);
- if(port)
- serverhost[port-argv[2]]=(char)0;
- }
- else
- strncpy(serverhost,SERVER,80);
-
- if(argc>3)
- strncpy(realname,argv[3],80);
- else {
- char *comma=strchr(passent->pw_gecos,',');
- strncpy(realname,passent->pw_gecos,80);
- if(comma)
- realname[comma-(passent->pw_gecos)]=(char)0;
- }
-
- if(argc>4)
- strncpy(user,argv[4],9);
- else
- strncpy(user,passent->pw_name,9);
-
- signal(SIGPIPE,(void (*)())signal_handler);
- signal(SIGHUP,(void (*)())show_split);
- signal(SIGINT,(void (*)())signal_handler);
- signal(SIGTERM,(void (*)())signal_handler);
- signal(SIGBUS,(void (*)())signal_handler);
- signal(SIGABRT,(void (*)())signal_handler);
- signal(SIGSEGV,(void (*)())signal_handler);
- signal(SIGALRM,(void (*)())signal_alarm);
-
- errno=0;
- if((sock=socket(AF_INET,SOCK_STREAM,0))>0) {
- server.sin_family=AF_INET;
- server.sin_port=htons(sport);
- fprintf(stderr,"Resolving %s...",serverhost); fflush(stderr);
- if((server.sin_addr.s_addr=resolver(serverhost))) {
- fputs("done\n",stderr);
- fflush(stderr);
-
- setsockopt(sock,SOL_SOCKET,SO_LINGER,0,0);
- setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,0,0);
- setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,0,0);
-
- fcntl(sock,F_SETFL,(fcntl(sock,F_GETFL)|O_NDELAY));
-
- fprintf(stderr,"Connecting to %s...",inet_ntoa(server.sin_addr));
- fflush(stderr);
-
- errno=0;
- if(connect(sock,(struct sockaddr *)&server,sizeof(server))) {
- if(errno!=EINPROGRESS && errno!=EWOULDBLOCK)
- exit_program(mystrerror(errno));
- else
- session=INPROGRESS;
- }
- else
- init_server();
-
- gethostname(hostname,64);
- process_server();
- }
- else
- exit_program("resolve failed");
- }
- else {
- fprintf(stderr,"Failed to allocate an AF_INET socket. (%s)\n", \
- mystrerror(errno));
- fflush(stderr);
- }
- }
-